LLM 基础速通
副标题:Token、上下文、温度、幻觉与 RAG(前端够用版)
姊妹篇(原理向):LLM 原理速览:Transformer、Attention 与工作机制(自注意力、分词/Token 计费机制、和「理解/推理/生成」的边界)
目标:用前端能理解的方式,把“够用的基础”讲清楚——你要能解释、能排障、能做产品决策。
目录
- (原理补充)LLM 原理:Transformer / Attention / Token 机制
- LLM 是什么:从“预测下一个词”到“产品能力”
- 2026 模型版图与选型:面试必须能“说清楚现在用什么”
- 推理模型(Reasoning Models):2024 年后最大的范式变化
- Token 与上下文窗口:为什么越聊越贵、越聊越跑偏
- 温度(Temperature)与 Top-p:如何控制“稳定 vs 发散”
- 幻觉:为什么会胡说,以及怎么降低
- Function Calling / Tools:让模型做“可控的事”
- RAG:文档问答/企业知识库的关键能力
- 前端工程师的“够用速记卡”
- 附:你可以直接抄走的“默认参数组合”
- 最小可运行 Demo(LLM 基础版)
- 完整可运行代码(Token/上下文估算)
(原理补充)LLM 原理:Transformer / Attention / Token 机制
若你需要比本章更“向下”的结构级解释(自注意力在做什么、Decoder-only 堆叠、BPE/子词与计费和粗估差在哪、“推理”与机制上是否等价),请阅读专题:LLM原理-Transformer与工作机制。本章专注应用与产品决策;该专题专注工作机制直觉。
LLM 是什么:从“预测下一个词”到“产品能力”
如果你是第一次接触 LLM,可以先把它理解为一个“读懂上下文后,持续预测下一段最可能文本”的系统。
这里有两个关键词:
- 读上下文:它不是凭空回答,而是根据你给的输入、系统规则、历史对话来判断接下来该说什么。
- 做预测:它每次不是“一次性写完整篇”,而是一步步预测下一个 token,再拼成整段回答。
你可以把它想成一个“非常强的自动补全器”,只不过它补全的单位不是几个字,而是整段推理、解释、代码、结构化数据。
这也是为什么它看起来像“会思考”:本质上是高质量的统计预测叠加了大量训练知识,而不是人类意识。
再用一个生活化例子帮助理解:
当你输入“请帮我写一份周报,要求包含本周完成、问题、下周计划”,LLM 会先根据“周报”这个任务模式预测结构,再在每个小节里继续预测更具体的句子。这就是“从预测到产品能力”的关键过程。
对你做应用开发来说,更重要的是:
- 能力边界:擅长总结、改写、生成、分类、对话、工具编排;不擅长保证事实正确
- 输出不确定:同样输入可能得到不同输出(可用参数控制)
- 对上下文敏感:你给它什么,它就按什么“演”
因此应用层的工作,本质是:把不确定的能力,变成可控的产品体验。
你可以用下面这个“输入到输出”微型过程建立直觉:
- 前端把用户问题和上下文发给服务端
- 服务端补充系统规则(如输出格式、风格、是否必须引用)
- LLM 基于完整上下文做逐 token 预测并返回
- 前端把结果渲染给用户,并做兜底(错误提示、重试、引用展示)
当你理解这 4 步后,很多“为什么它会胡说”“为什么它有时不稳定”“为什么要做 RAG/校验/工具调用”的问题就都能串起来了。
2026 模型版图与选型:面试必须能“说清楚现在用什么”
面试官常问“你们用什么模型、怎么选的”。死记型号会过期,关键是记住分层逻辑:先按“能力档位 + 部署方式 + 成本”分类,再按任务匹配。
按厂商/家族的当前主力(2026 年视角)
| 家族 | 代表型号(会迭代,记家族即可) | 定位 | 前端选型直觉 |
|---|---|---|---|
| OpenAI GPT | GPT-5 系列(含 mini/nano 档)、o 系列推理模型 | 通用旗舰 + 推理 | 综合能力强、生态全(Responses API、结构化输出、Realtime) |
| Anthropic Claude | Claude 4.x(Opus / Sonnet / Haiku) | 代码、长文档、Agent | 工具调用与长上下文稳,Agent/编码场景口碑好 |
| Google Gemini | Gemini 2.5 / 3(Pro / Flash) | 超长上下文 + 多模态 | 1M+ token 上下文、原生多模态、Flash 性价比高 |
| DeepSeek | DeepSeek-V3(通用)、R1(推理) | 开源/低成本推理 | 价格极低、可私有化,性价比党首选 |
| 阿里 Qwen | Qwen3 系列(含 MoE、稠密多档) | 开源全能 | 中文强、可本地部署、生态活跃 |
| 月之暗面 Kimi | Kimi K2 等 | 长上下文 / Agent | 国产长文与 Agent 方向 |
| Meta Llama | Llama 3.3 / 4 系列 | 开源自托管 | 需要完全私有化、可控权重时的底座 |
面试话术:“型号每季度都在变,我更关注三条选型轴:能力档位(旗舰/轻量/推理)、部署方式(API/私有化)、单位成本。落地时同一产品里我会做模型路由——简单任务走便宜的小模型,复杂/高价值任务走旗舰或推理模型。”
三个关键选型维度
- 能力档位:旗舰大模型(难任务、复杂推理)/ 轻量小模型(高频、低成本,如 mini/nano/flash/haiku)/ 推理模型(数学、规划、多步逻辑)。
- 部署方式:闭源 API(接入快、能力强、数据出域需评估合规)vs 开源自托管(数据不出域、可微调、需 GPU 运维)。
- 上下文与多模态:是否需要 100K+ / 1M 长上下文、是否需要图像/音频/视频原生输入。
成本直觉(数量级,不要背精确价)
- 轻量小模型 通常比旗舰便宜一个数量级以上,绝大多数高频请求应该走小模型。
- 推理模型 因为会生成大量“思考 token”,单次更贵、更慢,只在真正需要多步推理时用。
- 开源自托管 把“按 token 付费”换成“按 GPU 时长付费”,高并发稳定负载时更划算。
一个能直接讲的工程结论:默认小模型 + 关键路径升级旗舰 + 复杂推理才用推理模型 + 用 Prompt 缓存压成本,这套组合就是 2026 年“控成本又保质量”的标准答案。
推理模型(Reasoning Models):2024 年后最大的范式变化
这是近两年最重要的新概念,面试高频且很多人答不清。
它和普通模型有什么不同
- 普通(指令)模型:拿到问题基本“脱口而出”,直接预测答案 token。
- 推理模型(如 OpenAI o 系列、DeepSeek-R1、各家的“thinking”模式):在给出答案前,先在内部生成一长串思维链(chain-of-thought),用“推理时算力(test-time compute)”换取更高的正确率。它们多数是用强化学习训练出“先想后答”的习惯。
关键特征(对前端工程的直接影响)
- 更慢、首字延迟(TTFT)更高:因为要先“想”很久才出答案 → UI 上要做**“正在思考…”**的阶段提示,不能让用户以为卡死。
- 更贵:思考过程会消耗大量 reasoning tokens(通常计入输出计费)→ 成本要按“可见输出 + 隐藏思考”一起估。
- 思考过程通常被折叠/摘要:多数厂商不返回完整原始思维链,只给“思考摘要”。前端可做可展开的“思考过程”面板。
- 提示写法相反:推理模型不需要你手写“一步步想”的 CoT,过度的分步指令反而可能降低效果——给目标和约束就好(详见 Prompt工程)。
什么时候用 / 不用
- 该用:数学计算、代码调试、多步规划、复杂数据分析、Agent 任务编排。
- 别用:简单问答、改写、分类、格式化——用普通小模型又快又省。
面试一句话:“推理模型是用‘推理时算力’换准确率,适合难题;但慢且贵,所以我会把它放在‘判定为复杂任务’的分支上,简单任务仍走普通小模型。”
Token 与上下文窗口:为什么越聊越贵、越聊越跑偏
Token 是什么
你可以把 Token 粗略理解为“文本片段的计费单位”。中文通常 1 个汉字 ≠ 1 个 Token,但你不需要精确换算,关键是知道:
- 输入 Token:system + user + 历史对话 + 检索到的文档片段
- 输出 Token:模型生成的回答
- 成本 = 输入 + 输出(通常按 Token 计费)
一个可落地的 Token 预算算例(前端视角)
假设你做一个“文档问答”页面,想控制每次对话的成本上限。你可以把一次请求的 Token 拆成 4 块:
- system:规则与角色(例如 200 tokens)
- history:历史对话(例如 1500 tokens)
- rag_context:检索证据(例如 3 段 * 350 = 1050 tokens)
- user:用户问题(例如 80 tokens)
那么输入大约是:(200 + 1500 + 1050 + 80 = 2830) tokens
如果你把 max_tokens 设置为 600,那么单次请求的总量大约是:(2830 + 600 = 3430) tokens。
你可以据此在产品里做两件事:
- 成本可控:把
max_tokens、RAG 段数、history 长度变成硬限制 - 体验可解释:当超预算时提示“已自动压缩对话历史/减少引用段落”
实操建议:先定“每次回答允许的最大证据段数(TopN)”和“max_tokens”,再决定历史对话保留策略。
上下文窗口(Context Window)
上下文窗口是模型一次能“看到”的最大 Token 数。超出部分会被截断或需要你自己压缩/摘要。
产品层常见现象:
- 越聊越贵:历史对话越来越长
- 越聊越容易跑偏:历史里混入了错误/无关信息,模型被带偏
- 长文档问答不准:把整本文档塞进上下文不现实
应用层对策(你会在后续章节用到):
- 对话摘要:把历史压缩成结构化记忆(要点/偏好/约束)
- 检索替代堆上下文:用 RAG 只塞相关片段
- 限制输入输出:UI 侧限制字数、服务端限制 max_tokens
示例:对话摘要(Memory)怎么写才“能用”
很多项目的摘要失败,是因为把历史“概括成一段话”,结果信息丢失或不可控。建议用结构化摘要,并固定字段:
你是对话摘要器。请把以下对话压缩成“可用于后续对话”的结构化记忆。
输出为 JSON,字段必须包含:
- user_goal: 用户目标(1 句话)
- constraints: 约束(数组,最多 5 条)
- decisions: 已确认的关键决策(数组,最多 5 条)
- open_questions: 未解决问题(数组,最多 5 条)
- glossary: 专有名词解释(对象,可选)
规则:
- 不要编造;缺失就留空数组
- 严禁输出多余字段
前端怎么用这份摘要:
- UI 状态 → constraints/decisions:让“已选项/已确认”进入上下文
- 继续追问 → open_questions:直接用未解问题驱动下一轮追问
常见坑:上下文不是越长越好
- 把整篇文档塞进去:成本暴涨,还会稀释关键信息,准确率反而下降
- 把无关历史也带上:会把模型带偏(尤其在多任务对话里)
- 没有硬限制:上线后很容易被“长对话用户”拖垮成本
Prompt Caching(提示缓存):省钱又提速的关键手段
2024 年后各大厂商普遍支持 Prompt Caching:把重复出现的长前缀(如固定 system 提示、工具定义、知识库说明、长 few-shot 例子)缓存住,下次命中缓存的部分大幅降价(常见省 50%~90%)且更快。
- 命中前提:缓存按“前缀完全一致”匹配。所以工程上要把不变的内容放最前面,变化的内容(用户问题、当前时间)放最后。
- 典型收益:长 system 提示 + 多轮对话 + RAG 固定说明,命中缓存后省钱效果非常明显。
- 前端含义:拼 Prompt 的顺序要稳定——别每次把时间戳、随机 ID 插在最前面,否则永远命不中缓存。
这是“控成本”面试的高分点:“我把静态前缀(system、工具定义、知识库规则)固定在最前面以命中 Prompt 缓存,把动态内容放最后,长上下文场景成本能降一大截。”
温度(Temperature)与 Top-p:如何控制“稳定 vs 发散”
你可以把它理解成“随机性旋钮”:
- 温度低:更稳定、更像“按规则办事”(适合问答、抽取、格式化)
- 温度高:更发散、更有创意(适合文案、头脑风暴)
- Top-p:另一种控制采样范围的方式(实际使用中常与温度二选一或搭配)
应用建议(经验型):
- 结构化输出/需要稳定:温度低(或 Top-p 小一些)
- 创意生成:温度稍高
- 多步骤任务:把“生成”与“校验/格式化”拆成两次调用(一次负责想,另一次负责收敛)
示例:同一个任务,不同温度的差异
任务:把一段中文需求改写成 3 条验收标准。
- 温度低(更稳定):更像“按模板填空”,适合结构化、抽取、总结
- 温度高(更发散):会补充更多“想象的细节”,适合脑暴,但更容易跑题/编造
推荐默认值(可以当产品默认参数):
- 问答/总结/抽取:
temperature=0.2~0.4 - 写作/文案/创意:
temperature=0.7~1.0 - Top-p:如果使用
top_p,通常就把temperature固定较低(或反过来二选一),避免双重随机导致不可控
前端产品化建议:把参数变成“用户可理解的开关”
- “更严谨/更有创意”滑杆 → 映射到 temperature
- “回答更短/更详细” → 映射到 max_tokens + 章节要求(而不仅仅是 max_tokens)
幻觉:为什么会胡说,以及怎么降低
为什么会幻觉
模型的目标是“生成看起来合理的文本”,不是“保证事实正确”。当它缺信息时,可能会:
- 编造引用、编造数字、编造链接
- 把旧知识当新知识
- 把用户的暗示当事实
怎么降低(应用层可控手段)
从易到难给一组可落地的手段:
- 明确约束:不知道就说不知道;禁止编造引用/链接
- 要求引用证据:回答必须给出来源片段(RAG)
- 工具替代猜测:需要实时信息就调用工具/接口,不让它猜
- 分步推理外显/内隐:让模型先列检查清单再输出(或用“自检”二次调用)
- 输出校验:JSON schema 校验、字段缺失补问、格式不对重试
可直接复用的“拒答 + 引用”模板(推荐用于 RAG)
你是严谨的助手。你只能基于【证据】回答。
规则:
1) 如果证据不足以支持结论:请明确回答“根据当前证据无法确定”,并列出需要补充的信息。
2) 严禁编造链接、编号、数据、来源。
3) 每个关键结论后必须标注引用,如 [S1] [S2]。
输出格式:
- 结论(带引用)
- 依据(引用列表)
- 不确定点与需要补充的问题
示例:二次“自检”降低幻觉(便宜但有效)
第一次生成后,再用一个更短的检查 Prompt 做校验:
请检查下面回答是否存在“无证据推断/编造引用/数字不一致/与证据矛盾”。
若存在,请输出:问题列表 + 修正后的回答(仍需引用)。
实战经验:这类“自检”对引用完整性、格式稳定性提升明显,成本通常远低于一次完整重写。
Function Calling / Tools:让模型做“可控的事”
当你需要模型“做事”而不是“聊天”,最重要的思想是:
- 模型负责决策/抽取(要调用哪个工具、参数是什么)
- 系统负责执行(真正发请求、查库、算价格、读文件)
常见工具场景:
- 查询订单/权限判断
- 生成 PRD 的结构化字段(而不是一大段散文)
- 文档检索(先检索,再回答)
工程要点:
- 工具参数要可验证:字段类型、必填项、长度限制
- 工具输出要可追溯:日志里记录 tool 输入输出(脱敏)
- 避免越权:服务端再次做权限校验,不信任模型
示例:用 Tools 把“猜”变成“查”(端到端思路)
场景:用户问“我的订单 12345 现在是什么状态?”
如果让模型直接回答,它只能猜;正确做法是让模型调用工具查订单。
1)工具定义(JSON Schema 思路)
{
"name": "getOrderStatus",
"description": "查询订单状态",
"parameters": {
"type": "object",
"properties": {
"orderId": { "type": "string", "description": "订单号" }
},
"required": ["orderId"]
}
}
2)服务端执行(关键是:不信任模型、二次鉴权)
// 伪代码:服务端收到模型的 tool 调用请求后
async function handleGetOrderStatus(userId: string, orderId: string) {
// 1) 鉴权:这个 user 是否有权限查这个订单
await assertOrderPermission(userId, orderId);
// 2) 真查:从数据库/内部 API 查询
return await ordersService.getStatus(orderId);
}
3)把工具结果回注给模型生成“可解释回答”
让模型基于工具结果输出,同时要求“不确定就说不确定”,避免它补细节。
前端加分点:把工具执行过程做成“可展开的步骤”(类似调试面板),用户信任会显著提升。
原生结构化输出(Structured Outputs):别再只靠“重试”
早期做 JSON 输出只能“在 Prompt 里求模型输出 JSON + 校验失败就重试”,不稳定。现在主流 API 支持原生结构化输出,把“尽量是 JSON”变成“保证符合你给的 JSON Schema”:
- OpenAI:
response_format: { type: "json_schema", json_schema: {... , strict: true } },或工具调用的strict: true,由解码器约束生成,确保字段、类型、枚举都合法。 - 其他厂商:Gemini 的
responseSchema、各家“JSON mode / 受约束解码”等机制思路一致。
// OpenAI 风格:用 JSON Schema 约束输出(伪示意)
const res = await client.chat.completions.create({
model: "gpt-5-mini",
messages,
response_format: {
type: "json_schema",
json_schema: {
name: "prd",
strict: true,
schema: {
type: "object",
additionalProperties: false,
properties: {
title: { type: "string" },
items: {
type: "array",
items: {
type: "object",
additionalProperties: false,
properties: {
name: { type: "string" },
priority: { type: "string", enum: ["P0", "P1", "P2"] },
},
required: ["name", "priority"],
},
},
},
required: ["title", "items"],
},
},
},
});
工程含义(面试加分):
- 可靠性从“概率对”变成“结构必对”:仍要做业务级校验(数值范围、引用是否真实),但解析失败/字段缺失这类低级错误基本消除。
- 配合 TypeScript / Zod:很多团队用
zod定义 schema,再转成模型需要的 JSON Schema,前后端共用一套类型。 - 降级仍要留:少数模型/场景不支持时,回退到“Prompt 约束 + 校验重试”。
RAG:文档问答/企业知识库的关键能力
RAG(Retrieval-Augmented Generation)可以理解为:
先“检索相关资料”,再“基于资料回答”,并尽量“引用来源”。
它解决的是:把“我不知道”变成“我去文档里查一下再回答”。
典型流程(你后面会实战):
- 文档切分(chunk)
- 每个 chunk 做 Embedding(向量表示)
- 用户提问也做 Embedding
- 向量检索取 TopK 相关 chunk
- 把 chunk 作为“证据”塞进 Prompt,让模型回答并引用
关键点(很多项目翻车就翻在这里):
- 切分策略:太大检索不准,太小上下文不够
- 引用输出:让用户能点开“证据来源”
- 评估与迭代:用固定问题集回归测试命中率/引用率
图示:RAG 的最小可行 Pipeline(Mermaid)
示例:证据输入格式(让引用变得“可实现”)
把检索到的 chunk 组织成“可引用编号”,并带元数据:
【证据】
[S1] doc=《用户手册》 page=12 title=安装
内容:...(chunk 文本)
[S2] doc=《FAQ》 section=退款
内容:...(chunk 文本)
然后在规则里要求:
- 每个关键结论后必须写 [S1]/[S2]
- 没证据就拒答或提出需要补充的问题
最小评估表(作品集可直接用)
- 检索命中率:正确证据是否出现在 TopK
- 引用准确率:引用是否真的支撑结论
- 失败类型:没命中 / 命中但噪音大 / 引用缺失 / 生成跑题
前端工程师的“够用速记卡”
- Token/上下文
- 对话越长越贵、越容易跑偏:用摘要 + RAG + 限制
- 温度/Top-p
- 低:稳定;高:发散;结构化输出优先低
- 幻觉
- 靠约束 + 引用 + 工具 + 校验降低
- Tools / 结构化输出
- 模型决定、系统执行;权限/校验在服务端做二次防线
- 用原生 Structured Outputs(JSON Schema strict)保证结构,少靠重试
- 推理模型
- 难题才用(数学/代码/规划);更慢更贵;UI 要有“思考中”提示
- 成本
- 默认小模型 + 关键路径升级 + Prompt 缓存(静态前缀放最前)
- RAG
- 企业知识库/文档问答核心;切分、检索、引用、评估缺一不可
附:你可以直接抄走的“默认参数组合”
- 结构化问答(带引用)
- temperature:0.2~0.4
- max_tokens:400~800(视你的 UI 长度)
- RAG:TopK=10,重排后 TopN=3~5(塞进 Prompt)
- 规则:必须引用;无证据拒答;输出固定结构
- 创意写作(不需要引用)
- temperature:0.8~1.0
- max_tokens:800~1500
- 规则:先给大纲再展开,避免跑题
最小可运行 Demo(LLM 基础版)
目标:用一个最小脚本跑通“预算估算 → 调用参数 → 输出校验”的闭环。
最小可运行代码(Token 预算 + 调用参数示例)
// demo-llm-budget.ts(伪代码)
function roughTokenEstimate(text: string) {
// 粗略估算:中文按 1 字 ≈ 1.3 token,英文按 1 单词 ≈ 1 token
const chineseChars = text.match(/[\u4e00-\u9fff]/g)?.length || 0;
const words = text.split(/\s+/).filter(Boolean).length;
return Math.ceil(chineseChars * 1.3 + words);
}
const system = "你是严格助手,必须引用来源。";
const user = "公司年假怎么计算?";
const rag = "证据片段..."; // 模拟RAG
const inputTokens =
roughTokenEstimate(system) + roughTokenEstimate(user) + roughTokenEstimate(rag);
const maxTokens = 600;
console.log("inputTokens:", inputTokens);
console.log("maxTokens:", maxTokens);
完整 Demo 结构(LLM 基础最小骨架)
demo-llm-basic/
scripts/
demo-llm-budget.ts
README.md
常见坑排查清单
- 预算超标:RAG 片段过长 → 减少 TopN 或做摘要
- 温度太高:结构化输出变得不稳定 → 降到 0.2~0.4
- 引用缺失:Prompt 未强制引用 → 加“必须引用”规则
完整可运行代码(Token/上下文估算)
源码目录:
docs/demos/token-demo
node docs/demos/token-demo/index.js